package cn.calm.xhtml.impl;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import cn.calm.xhtml.api.Namespace;
import cn.calm.xhtml.api.NodeProcess;
import cn.calm.xhtml.api.Tag;
import cn.calm.xhtml.api.Template;
import cn.calm.xhtml.api.TemplateEngine;
import cn.calm.xhtml.api.TemplateLoader;
import cn.calm.xhtml.api.exception.TemplateNotFoundException;
import cn.calm.xhtml.api.exception.XhtmlException;

public class DefaultTemplateEngine implements TemplateEngine {
	private Logger logger = LoggerFactory
			.getLogger(DefaultTemplateEngine.class);
	private List<TemplateLoader> loaders;
	private static final Map<String, Map<String, Class<NodeProcess>>> handlers = new HashMap<String, Map<String, Class<NodeProcess>>>();

	/**
	 * 默认模板引擎 初始化时加载所有标签
	 */
	public DefaultTemplateEngine() {
		try {
			load();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Template getTemplate(String template) {
		if (loaders == null) {
			throw new XhtmlException("TemplateLoader is not config ");
		}
		for (TemplateLoader loader : loaders) {
			URL url = loader.loadTemplate(template);
			if (url != null) {
				return new DefaultTemplate(this, url);
			}
		}
		throw new TemplateNotFoundException("Can't find template:" + template);

	}

	@Override
	public void setTemplateLoaders(List<TemplateLoader> loader) {
		this.loaders = loader;
	}

	@Override
	public void setTemplateLoader(TemplateLoader loader) {
		if (loaders == null) {
			loaders = new ArrayList<TemplateLoader>();
		}
		loaders.add(loader);
	}

	/**
	 * 加载所有cn.calm包下的标签
	 * 
	 * @throws URISyntaxException
	 */
	@SuppressWarnings("unchecked")
	private void load() throws URISyntaxException {
		// 查找所有cn.calm包下的类文件
			PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
			org.springframework.core.io.Resource[] resources;
			try {
				resources = resolver.getResources("classpath*:/META-INF/namespace/*.xml");
				JAXBContext context = JAXBContext.newInstance(Namespace.class);
				Unmarshaller createUnmarshaller = context.createUnmarshaller();
				for (org.springframework.core.io.Resource u : resources) {
						logger.info(u.toString());
						try {
							Namespace namespace = (Namespace) createUnmarshaller
									.unmarshal(u.getInputStream());
						
						String uri = namespace.getUri();
						Map<String, Class<NodeProcess>> map = handlers.get(uri);
						if (map == null) {
							map = new HashMap<>();
							handlers.put(uri, map);
						}
						List<Tag> tags = namespace.getTags();
						for (Tag t : tags) {
							String name = t.getName().toLowerCase();
							Class<NodeProcess> class1 = map.get(name);
							if (class1 == null) {
								String className = t.getClassName();
								Class<?> forName = Class.forName(className);
								map.put(name, (Class<NodeProcess>) forName);
							} else {
								logger.equals(name + "is regedit");
							}
						}
					} catch (JAXBException | ClassNotFoundException e) {
						e.printStackTrace();
					}
				}
			} catch (IOException | JAXBException e) {
				e.printStackTrace();
			}
			
	}

	/**
	 * 获得所有的父类及接口
	 * 
	 * @param type
	 *            类的类型
	 * @return 所有父类及接口集合
	 */
	public List<Class<?>> getInter(Class<?> type) {
		List<Class<?>> result = new ArrayList<>();
		if (type.equals(Object.class)) {
			return result;
		}
		Class<?>[] interfaces = type.getInterfaces();
		List<Class<?>> asList = Arrays.asList(interfaces);
		result.addAll(asList);
		Class<?> superclass = type.getSuperclass();
		if (superclass == null) {
			return result;
		}
		result.addAll(getInter(superclass));
		return result;
	}

	@Override
	public Map<String, Map<String, Class<NodeProcess>>> getHandlers() {
		return Collections.unmodifiableMap(handlers);
	}

	public void setHandlers(
			Map<String, Map<String, Class<NodeProcess>>> handlers) {
		DefaultTemplateEngine.handlers.putAll(handlers);
	}

}
